/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package z.h.w.jar.data.time;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import z.h.w.jar.data.time.period.Lastable;
import z.h.w.jar.kit.method.To;

/**
 *
 * @author EnzoZhong
 * @date 2011.11.10
 */
@SuppressWarnings ( "serial" )
public class Time extends AbstractTime {

      private DecimalFormat df = new DecimalFormat ( "0.00000" );
      private Locale locale = Locale.getDefault ();

      /**
       * 私有构造器
       */
      private Time () {
      }

      private Time ( Date date ) {
            super ( date );
      }

      /**
       *
       * @param date
       */
      private Time ( String date ) {
            super ( date );
      }

      /**
       * 通过long时间初始化
       *
       * @param longNum
       */
      private Time ( Long longNum ) {
            super ( longNum );
      }

      /**
       *
       * @return
       */
      public static Time born () {
            return new Time ();
      }

      /**
       *
       * @param multiple param unit
       *
       * @param unit
       *
       * @return
       */
      public static Time born ( Double multiple , Unit unit ) {
            return born ().offset ( multiple , unit );
      }

      /**
       * 根据输入的long来生成时间
       *
       * @param time
       *
       * @return
       */
      public static Time born ( Long time ) {
            return new Time ( time );
      }

      /**
       *
       * @param time
       *
       * @return
       */
      public static Time born ( Date time ) {
            return new Time ( time );
      }

      /**
       *
       * @param time
       *
       * @return
       */
      public static Time born ( Integer time ) {
            return new Time ( String.valueOf ( time ) );
      }

      public static Time born ( Integer year , Integer month ) {
            return born ( year , month , 1 );
      }

      public static Time born ( Integer year , Integer month , Integer day ) {
            String strMonth = month <= 9 ? "0" + month : month + "";
            String strDay = day <= 9 ? "0" + day : day + "";
            return Time.born ( year + "" + strMonth + "" + strDay );
      }

      /**
       * 通过匹配字符串来生成时间
       *
       * @param time
       * @return
       */
      public static Time born ( String time ) {
            return new Time ( time );
      }

      /**
       * 通过lastable的其实时间来生成时间
       *
       * @param lastable
       * @return
       */
      public static Time born ( Lastable lastable ) {
            return lastable.getStart ();
      }

      @Override
      public Time offset ( Double multiple , Unit unit ) {
            return new Time ( this.getTime () + unit.convert ( multiple ).longValue () );
      }

      @Override
      public Double to ( Time time , Unit unit ) {
            Long date1 = this.getTime ();
            Long date2 = time.getTime ();
            Double dval = new Double ( Math.abs ( date1 - date2 ) );
            String format = df.format ( dval / unit.convert ( 1.0 ) );
            return new Double ( format );
      }

      @Override
      public Double to ( Unit unit ) {
            return to ( Time.born () , unit );
      }

      @Override
      public Double to ( String time , Unit unit ) {
            return to ( To.string2Time ( time ) , unit );
      }

      @Override
      @Deprecated
      public Time[] to ( Attr find , String regex , Integer size , Double mul , Unit unit ) {
            Time time = this;
            List<Time> tmp = new ArrayList<> ( 50 );
            if ( time.tell ( find ).equalsIgnoreCase ( regex ) ) {
                  tmp.add ( time );
            }
            while ( tmp.size () < size ) {
                  time = time.offset ( mul , unit );
                  if ( time.tell ( find ).equalsIgnoreCase ( regex ) ) {
                        tmp.add ( time );
                  }
            }
            return To.list2Array ( tmp );
      }

      @Override
      public Time to ( Attr find , String regex , Double mul , Unit unit ) {
            return to ( find , regex , 1 , mul , unit )[0];
      }

      @Deprecated
      @Override
      public Time to ( Attr find , String regex , Double mul , Unit unit , Integer index ) {
            return to ( find , regex , index , mul , unit )[index - 1];
      }

      @Override
      public String tell ( Attr attr ) {
            AttrAct na = new AttrAct ();
            return na.getField ( this , attr );
      }

      @Override
      public String tellLocale ( Attr attr ) {
            AttrAct na = new AttrAct ();
            return na.getFieldLocale ( this , attr );
      }

      @Override
      public String[] tell ( Attr... attr ) {
            Integer len = attr.length;
            String[] array = new String[ len ];
            for ( Integer x = 0 ; x < len ; x ++ ) {
                  array[x] = tell ( attr[x] );
            }
            return array;
      }

      @Override
      public Time keep ( Attr attr ) {
            return born ( toString ( attr ) );
      }

      /**
       * 求目标时间与自身时间的位置关系
       *
       * @param place time
       * @param time
       *
       * @return
       */
      @Override
      public Boolean is ( Place place , Time time ) {
            PlaceAct placeAct = new PlaceAct ();
            return placeAct.place ( this , place , time );
      }

      @Override
      public Boolean is ( Place place , Date date ) {
            PlaceAct placeAct = new PlaceAct ();
            return placeAct.place ( this , place , born ( date ) );
      }

      /**
       *
       * @return
       */
      public static Integer howOldAmI () {
            Time now = Time.born ();
            Time born = Time.born ( "19880808" );
            return born.to ( now , Unit.YEAR ).intValue ();
      }

      public Locale getLocale () {
            return locale;
      }

      public void setLocale ( Locale locale ) {
            this.locale = locale;
      }

      @Override
      public String toString () {
            String rail = "-";
            String space = " ";
            String colon = ":";
            StringBuffer sb = new StringBuffer ();
            sb.append ( tell ( Attr.CENTURY ) ).append ( space );
            sb.append ( tell ( Attr.ERA ) ).append ( space );
            sb.append ( tell ( Attr.ZODIAC ) ).append ( space );
            sb.append ( tell ( Attr.YEAR ) ).append ( rail );
            sb.append ( tell ( Attr.MONTH ) ).append ( rail );
            sb.append ( tell ( Attr.DAY ) ).append ( space );
            sb.append ( tell ( Attr.SEASON ) ).append ( space );
            sb.append ( tell ( Attr.HOROSCOPE ) ).append ( space );
            sb.append ( tell ( Attr.WEEK ) ).append ( space );
            sb.append ( tell ( Attr.EANPN ) ).append ( space );
            sb.append ( tell ( Attr.HOUR ) ).append ( colon );
            sb.append ( tell ( Attr.MINUTE ) ).append ( colon );
            sb.append ( tell ( Attr.SECOND ) ).append ( colon );
            sb.append ( tell ( Attr.MILLISECOND ) );
            return sb.toString ();
      }

      public String toString ( Attr attr ) {
            StringBuffer sb = new StringBuffer ();
            switch ( attr ) {

                  case YEAR: {
                        sb.append ( this.tell ( Attr.YEAR ) );
                        sb.append ( "-01-01 00:00:00" );
                        break;
                  }
                  case MONTH: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) );
                        sb.append ( "-01 00:00:00" );
                        break;
                  }
                  case DAY: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.DAY ) );
                        sb.append ( " 00:00:00" );
                        break;
                  }
                  case HOUR: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.DAY ) ).append ( " " );
                        sb.append ( this.tell ( Attr.HOUR ) );
                        sb.append ( ":00:00" );
                        break;
                  }
                  case MINUTE: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.DAY ) ).append ( " " );
                        sb.append ( this.tell ( Attr.HOUR ) ).append ( ":" );
                        sb.append ( this.tell ( Attr.MINUTE ) );
                        sb.append ( ":00" );
                        break;
                  }
                  case SECOND: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.DAY ) ).append ( " " );
                        sb.append ( this.tell ( Attr.HOUR ) ).append ( ":" );
                        sb.append ( this.tell ( Attr.MINUTE ) ).append ( ":" );
                        sb.append ( this.tell ( Attr.SECOND ) );
                        break;
                  }
                  default: {
                        sb.append ( this.tell ( Attr.YEAR ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.MONTH ) ).append ( "-" );
                        sb.append ( this.tell ( Attr.DAY ) ).append ( " " );
                        sb.append ( this.tell ( Attr.HOUR ) ).append ( ":" );
                        sb.append ( this.tell ( Attr.MINUTE ) ).append ( ":" );
                        sb.append ( this.tell ( Attr.SECOND ) );
                        break;
                  }
            }
            return sb.toString ();
      }

      public Boolean isPass () {
            Long time = this.getTime ();
            Long now = new Date ().getTime ();
            return now > time;
      }

      @Override
      public Boolean equals ( Time time , Attr... attrArray ) {
            String string1 = array2String ( this.tell ( attrArray ) );
            String string2 = array2String ( time.tell ( attrArray ) );
            return string1.equalsIgnoreCase ( string2 );
      }

      private String array2String ( String[] array ) {
            StringBuffer stringBuffer = new StringBuffer ();
            for ( String str : array ) {
                  stringBuffer.append ( str );
            }
            return stringBuffer.toString ();
      }

      @Override
      public Boolean same ( Attr attr ) {
            Time now = Time.born ();
            return now.toString ( attr ).equalsIgnoreCase ( this.toString ( attr ) );
      }

      public Time next ( Attr attr ) {
            switch ( attr ) {
                  case YEAR:
                        return keepOffsetKeep ( attr , Unit.YEAR );
                  case MONTH:
                        return keepOffsetKeep ( attr , Unit.MONTH );
                  case DAY:
                        return keepOffsetKeep ( attr , Unit.DAY );
                  default:
                        return this;
            }
      }

      private Time keepOffsetKeep ( Attr attr , Unit unit ) {
            return this.keep ( attr ).offset ( 1.19860805 , unit ).keep ( attr );
      }

}
